#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include "calculater.h"

#define BUFFSIZE 4096
#define LISTEN_BAKLOG 128
#define SERVER_PORT 2222
#define ERR_EXIT(m) (perror(m), exit(EXIT_FAILURE))

int listen_ftp(int server_port)
{
	int listenfd, on;
	struct sockaddr_in saddr;

	if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		ERR_EXIT("socket");
	on = 1;
	if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
		ERR_EXIT("setsockopt");
	memset(&saddr, 0, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(SERVER_PORT);
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
	if(bind(listenfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
		ERR_EXIT("bind");
	if(listen(listenfd, LISTEN_BAKLOG) < 0)
		ERR_EXIT("listen");
	return listenfd;
}

void do_client(int connfd)
{
	int ret;
	char buf[BUFFSIZE] = "";

	for( ; ; ) {
		if((ret = read(connfd, buf, sizeof(buf))) < 0)
			ERR_EXIT("read");
		buf[ret] = '\0';
		if(!strcmp("quit", buf))
			break;
		snprintf(buf, sizeof(buf), "%.16g", bc(buf)); 
		if(write(connfd, buf, strlen(buf)) < 0)
			ERR_EXIT("write");
	}
	close(connfd);
}

void start_server(int listenfd)
{
	int connfd;

	if(signal(SIGCHLD, SIG_IGN) < 0) 
		ERR_EXIT("signal");
	for( ; ; ) {
		if((connfd = accept(listenfd, NULL, NULL)) < 0)
			ERR_EXIT("accept");
		switch(fork()) {
		case -1:
			ERR_EXIT("fork");
		case 0:
			close(listenfd);
			do_client(connfd);
			exit(EXIT_SUCCESS);
		default:
			close(connfd);
		}
	}
}

int main()
{
	int listenfd;

	listenfd = listen_ftp(SERVER_PORT);
	start_server(listenfd);
	return 0;
}
